<template>
  <div
    :class="[
            `${classPrefix}`,
            computedSize && `${classPrefix}--${computedSize}`,
            disabled && `is-disabled`
         ]"
    v-click-outside.capture="handleOutsideClick"
  >
    <div
      ref="reference"
      :class="[`${classPrefix}__reference`]"
      :tabindex="referenceTabIndex"
      @keydown.esc.prevent="handleKeydown"
      @keydown.enter.prevent="handleKeydown"
      @keydown.down.prevent="handleKeydown"
      @keydown.up.prevent="handleKeydown"
      @keydown.tab.prevent="handleKeydown"
    >
      <select-reference />
    </div>
    <transition :name="transition">
      <Drop
        v-show="visible && !disabled"
        ref="dropDown"
        :reference="this.$refs.reference"
        :placement="placement"
        :render-html="renderHtml"
        :dropdownMatchSelectWidth="dropdownMatchSelectWidth"
        v-model="visible"
      >
        <div
          ref="scrollOuter"
          :class="[`${classPrefix}__drop-inner`,size && `${classPrefix}__drop-inner--${size}`,]"
          :style="dropInnerStyle"
        >
          <scroll ref="scroll" size="small" :scrollOption="{scrollPanel:false}">
            <div ref="scrollInner">
              <div v-if="loading" :class="[`${classPrefix}__loading`]">
                <Icon type="loading" class="animation-rotate"></Icon>
                {{addTo('m.select.loading')}}
              </div>
              <div v-else-if="isEmpty" :class="[`${classPrefix}__empty`]">{{localEmptyText}}</div>
              <template v-if="renderType === 'option'">
                <Option
                  v-if="allowCreate && allowCreateOption"
                  allowCreate
                  :label="allowCreateOption.label"
                  :value="allowCreateOption.value"
                ></Option>
                <optionRender :option="currentOption"></optionRender>
              </template>
              <template v-if="renderType === 'slot'">
                <Option
                  v-if="allowCreate && allowCreateOption"
                  allowCreate
                  :label="allowCreateOption.label"
                  :value="allowCreateOption.value"
                ></Option>
                <slot></slot>
                <template v-for="item in currentAllowCreateOption">
                  <Option :key="item.value" :label="item.label" :value="item.value"></Option>
                </template>
              </template>
            </div>
          </scroll>
        </div>
      </Drop>
    </transition>
  </div>
</template>

<script>
import Config from "/src/config";
import { directive as clickOutside } from "v-click-outside-x";
import SelectReference from "./selectReference.vue";
import Scroll from "/src/components/scroll";
import Drop from "/src/components/base/drop";
import Locale from "/src/utils/locale";
import mixins from "./mixins";
import optionRender from "./optionRender";
import Option from "./option";
import { findComponent } from "/src/utils/tools";

export default {
  name: "Select",
  directives: { clickOutside },
  mixins: [Locale, mixins],
  provide() {
    return {
      selectRoot: this,
    };
  },
  props: {
    value: [String, Number, Array],
    name: String,
    placeholder: String,
    disabled: Boolean,
    size: {
      type: String,
      default() {
        return !this.$MONKEY || this.$MONKEY.size === ""
          ? "default"
          : this.$MONKEY.size;
      },
      validator(value) {
        return ["mini", "small", "default", "large"].includes(value);
      },
    },
    option: Array,
    transition: {
      type: String,
      default: "slideUp",
    },
    multiple: Boolean,
    clearable: Boolean,
    emptyText: String,
    filterable: Boolean, // 开启搜索
    remote: Boolean, // 开启远程搜索
    loading: Boolean, // 正在远程搜索
    allowCreate: Boolean, // 是否允许新建
    // 多选限制最多显示的tag数量，其他折叠 0不折叠
    maxTagCount: {
      type: Number,
      default: 0,
    },
    // 超出最大数量限制时显示的内容，参数为当前选中的数量
    maxTagText: Function,
    // 多选限制选择的数量 0不限制
    multipleLimit: {
      type: Number,
      default: 0,
    },
    maxHeight: {
      type: [String, Number],
      default: "200px",
    },
    placement: {
      type: String,
      default: "bottom-start",
    },
    valueLable: Boolean,
    dropdownMatchSelectWidth: {
      type: Boolean,
      default: true,
    },
    renderHtml: {
      type: [HTMLElement, Boolean],
      default: false,
    },
  },
  data() {
    return {
      optionPrefix: Config.classPrefix + "-option",
      classPrefix: Config.classPrefix + "-select",
      componentName: "Select",
      form: findComponent(this, "Form"),
    };
  },
  computed: {
    computedSize() {
      if (this.size !== "default") return this.size;
      if (this.form && this.form.size !== "default") return this.form.size;
      return this.size;
    },
    isEmpty() {
      if (this.isFilter) {
        if (this.allowCreate && this.allowCreateOption) return false;
        return !this.filterableValue.length;
      }
      return !this.currentOption.length;
    },
    localEmptyText() {
      return this.emptyText || this.addTo("m.select.emptyData");
    },
    dropInnerStyle() {
      return { height: this.scrollInnerHeight + "px" };
    },
    referenceTabIndex() {
      return this.disabled || this.filterable ? "-1" : "0";
    },
    // 开启多选限制的，此时除了已经选中的option 其他option全部disabled
    openMultipleLimitDisabled() {
      return (
        this.multiple &&
        this.multipleLimit > 0 &&
        this.currentValue.length >= this.multipleLimit
      );
    },
    // 计算多选时 超出限制数量时的截取
    localCurrentSelectedItems() {
      const data = this.currentSelectedItems;
      const maxTagCount = this.maxTagCount;
      if (this.multiple && maxTagCount > 0 && data.length > maxTagCount) {
        return data.slice(0, maxTagCount);
      }
      return data;
    },
    // 计算多选时 超出显示数量显示的文本
    localMaxTagText() {
      const data = this.currentSelectedItems;
      const maxTagCount = this.maxTagCount;
      let maxTagText = `+ ${data.length - maxTagCount}...`;
      if (this.maxTagText && typeof this.maxTagText === "function") {
        maxTagText = this.maxTagText(data.length - maxTagCount);
      }
      return maxTagText;
    },
    // 计算多选时 是否超出限制数量
    showMaxTagText() {
      const data = this.currentSelectedItems;
      const maxTagCount = this.maxTagCount;
      return this.multiple && maxTagCount > 0 && data.length > maxTagCount;
    },
  },
  components: {
    SelectReference,
    Drop,
    Scroll,
    optionRender,
    Option,
  },
};
</script>
